#include "crecord.h"
#include "public_define.h"
#include "common_opr_string.h"

#include "json/json.h"
#include "common_opr_system.h"
string CRecord::SftVersion;
string CRecord::DiruanVersion;//之前用getversion s 记录的地软版本号；废弃，用topic
string CRecord::VinVersion;
string CRecord::Version_total;
string CRecord::Version_total_2;

string CRecord::ProtoInfo;

string CRecord::C2Version;

CRecord::CRecord(const std::string &file_name, bool compress)
    : file_name_(file_name), m_needCompress(compress)
{
    if (m_needCompress)
    {
        KRawDataBufferMaxSize = 1024 * 1024; // 1M
    }
    else
    {
        KRawDataBufferMaxSize = KPageSize * 2560; // 10M
    }
    // std::cout << "CRecord::CRecord" << std::endl;
}

CRecord::CRecord(const CRecord& other) {
    // 深拷贝所有成员变量
    file_name_ = other.file_name_;
    is_close_ = other.is_close_;
    write_eror = other.write_eror;
    m_needCompress = other.m_needCompress;
    KRawDataBufferMaxSize = other.KRawDataBufferMaxSize;
    
    // 拷贝data_write_buf_
    data_buf_cur_size_ = other.data_buf_cur_size_;
    data_write_buf_ = std::make_unique<char[]>(KRawDataBufferMaxSize);
    memcpy(data_write_buf_.get(), other.data_write_buf_.get(), data_buf_cur_size_);
    
    // 其他成员变量的拷贝
    proto_content_ = other.proto_content_;
    os = other.os; // 注意：如果os是文件指针，可能需要重新打开
    fd_ = other.fd_; // 同样，fd_可能需要重新打开
}

CRecord& CRecord::operator=(const CRecord& other) {
    if (this == &other) return *this;
    
    file_name_ = other.file_name_;
    is_close_ = other.is_close_;
    write_eror = other.write_eror;
    m_needCompress = other.m_needCompress;
    KRawDataBufferMaxSize = other.KRawDataBufferMaxSize;
    
    // 释放当前的data_write_buf_
    data_write_buf_.reset();
    
    // 拷贝data_write_buf_
    data_buf_cur_size_ = other.data_buf_cur_size_;
    data_write_buf_ = std::make_unique<char[]>(KRawDataBufferMaxSize);
    memcpy(data_write_buf_.get(), other.data_write_buf_.get(), data_buf_cur_size_);
    
    // 其他成员变量的赋值
    proto_content_ = other.proto_content_;
    os = other.os; // 同样，os可能需要重新打开
    fd_ = other.fd_; // 同样，fd_可能需要重新打开
    
    return *this;
}

CRecord::~CRecord()
{
    if (!is_close_)
    {
        Close();
    }
}

void CRecord::Init()
{
    int res = posix_memalign((void **)&data_write_buf_, 4096, KRawDataBufferMaxSize);
    if (res != 0)
    {
        Log_Info("init recorder buf failed!");
        return;
    }

    if (m_needCompress)
    {
        os = gzopen(file_name_.c_str(), "wb");
        if (os == nullptr)
        {
            std::cerr << "file open failed! Please check recordFilePos is exist?" << file_name_ << std::endl;
            return;
        }
    }
    else
    {
        fd_ = open(file_name_.c_str(), O_WRONLY | O_CREAT | O_DIRECT, 0777);
        if (fd_ == -1)
        {
            std::cerr << "file open failed! Please check recordFilePos is exist?" << file_name_ << std::endl;
            return;
        }
    }

    KDatHead file_head;
    file_head.version = 1.2;
    file_head.protoContentSize = ProtoInfo.size();;
    file_head.commentLength = Version_total_2.size();//版本信息等先写在 file_head 结构后面，用commentLength表示大小
    // write file head
    memcpy(&data_write_buf_[data_buf_cur_size_], (char *)&file_head, sizeof(file_head));
    data_buf_cur_size_ += sizeof(file_head);

    // write proto content
    memcpy(&data_write_buf_[data_buf_cur_size_], ProtoInfo.c_str(), ProtoInfo.size());
    data_buf_cur_size_ += ProtoInfo.size();

    // write commentLength
    memcpy(&data_write_buf_[data_buf_cur_size_], Version_total_2.c_str(), Version_total_2.size());
    data_buf_cur_size_ += Version_total_2.size();

}

void CRecord::Record(const std::string &data)
{
    if (write_eror)
    {
        return;
    }    
    MoveToRawdataBufAndWriteWhenBufFull(data);
}

void CRecord::MoveToRawdataBufAndWriteWhenBufFull(const std::string &rdata)
{
    int rdata_size = rdata.size();
    if (data_buf_cur_size_ + rdata_size <= KRawDataBufferMaxSize)
    {
        //拷贝
        memcpy(&data_write_buf_[data_buf_cur_size_], &rdata[0], rdata_size);
        data_buf_cur_size_ += rdata_size;
    }
    else
    {
        size_t copy_len = KRawDataBufferMaxSize - data_buf_cur_size_;
        size_t left_len = rdata_size - copy_len;
        memcpy(&data_write_buf_[data_buf_cur_size_], &rdata[0], copy_len);

        if (m_needCompress)
        {
            int res = gzwrite(os, data_write_buf_.get(), KRawDataBufferMaxSize);
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            if (res == -1)
            {
                write_eror = true;
                Log_Info("write data met error");
                string diagStr = strerror(errno);
                diagStr += ";errno:" + to_string(errno) + ";";
                // ModifyDiagnosisSts(4, diagStr);
                return;
            }
        }
        else
        {
            int res = write(fd_, data_write_buf_.get(), KRawDataBufferMaxSize);
            // Log_Info("Write file: {} cursize: {} fileName: {}", to_string(res), data_buf_cur_size_, file_name_);
            if (res == -1)
            {
                write_eror = true;
                Log_Info("write data met error");
                string diagStr = strerror(errno);
                diagStr += ";errno:" + to_string(errno) + ";";
                // ModifyDiagnosisSts(4, diagStr);
                return;
            }
        }

        //拷贝剩余头
        memcpy(&data_write_buf_[0], &rdata[copy_len], left_len);
        data_buf_cur_size_ = left_len;
    }
}

void CRecord::Close()
{
    is_close_ = true;
    // Log_Info("CRecord close");

    if (m_needCompress)
    {
        int res = gzwrite(os, data_write_buf_.get(), data_buf_cur_size_);
        (void)res;
        if (os != nullptr) 
        {
            gzclose(os);
            os = nullptr; // 防止悬挂指针
        }
    }
    else
    {
        if (data_buf_cur_size_ != 0)
        {
            // int residues = data_buf_cur_size_ % KPageSize;
            int quotient = data_buf_cur_size_ / KPageSize;

            int write_byte = (quotient + 1) * KPageSize;
            int more_byte = write_byte - data_buf_cur_size_;

            int res = write(fd_, data_write_buf_.get(), write_byte);
            if (res == -1)
            {
                close(fd_);
                Log_Info("write data met error");
                string diagStr = strerror(errno);
                diagStr += ";errno:" + to_string(errno) + ";";
                // ModifyDiagnosisSts(4, diagStr);
                return;
            }
            //删除多写入的字节
            off_t curpos = lseek(fd_, 0, SEEK_CUR);
            // Log_Info("Write file {}  cursize: {} fileName: {}", res, data_buf_cur_size_, file_name_);
            if (ftruncate(fd_, curpos - more_byte) == -1)
            {
                close(fd_);
                Log_Info("ftruncate extra byte error");
                return;
            }
        }
        if (fd_ != -1) {
            close(fd_);
        }
        fd_ = -1;
    }

    Log_Info("the record {} is over ", file_name_);
}

//C3B 没有run.sh脚本，需要解析version.json内容
bool CRecord::getC3BVersion()
{
    try
    {
        /* code */
        std::string c2_integration_version = "";
        std::string c2_soc_version = "";
        std::string c2_mcu_version = "";
        std::string c2_switch_version = "";
        std::string swc_interface_software_version = "";
        std::string jsonString="";
        // 配置文件若不存在,报错
        if(!CommonOprSystem::isPathExist(global_data::g_hardSoftwareVersion_path))
        {
            Log_Info("error g_hardSoftwareVersion_path not exist:{}",global_data::g_hardSoftwareVersion_path);
            return false;
        }
        // 读取配置文件内容
        CommonOprSystem::readFileAllOnce(global_data::g_hardSoftwareVersion_path, jsonString);

        if (jsonString.empty())
        {
            Log_Info("read g_hardSoftwareVersion_path file error");
            return false;
        }
        Json::Reader reader;
        Json::Value root;
        if (reader.parse(jsonString, root) && root.isMember("versions"))
        {
        const Json::Value& versions = root["versions"];
        for (const Json::Value& version : versions) 
        {
                const string& name = version["name"].asString();

                if (name == "mpu_hw") 
                {
                    c2_integration_version = version["version"].asString();
                }

                if (name == "mpu_sw") 
                {
                    c2_soc_version = version["version"].asString();
                    swc_interface_software_version = version.get("swc_interface_software_version", "").asString();

                    const Json::Value& items = version["items"];
                    for (const Json::Value& item : items) {
                        const string& item_name = item["name"].asString();

                        if (item_name == "pipelineitem") {
                            const Json::Value& pipeline_items = item["items"];
                            for (const Json::Value& pipeline_item : pipeline_items) {
                                const string& pipeline_name = pipeline_item["name"].asString();
                                if (pipeline_name == "mcu") {
                                    c2_mcu_version = pipeline_item["version"].asString();
                                    break;
                                }
                            }
                        }

                        if (item_name == "systems") {
                            const Json::Value& systems_items = item["items"];
                            for (const Json::Value& system_item : systems_items) {
                                const string& system_name = system_item["name"].asString();
                                if (system_name == "mpu_switch") {
                                    c2_switch_version = system_item["version"].asString();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        else
        {
            Log_Info("g_hardSoftwareVersion_path parse error");
            return false; 
        }
        Log_Info("c3_integration_version:{},c3_soc_version:{},c3_mcu_version:{},c3_switch_version:{},swc_interface_software_version:{}",c2_integration_version,c2_soc_version,c2_mcu_version,c2_switch_version,swc_interface_software_version);
        SftVersion="\nc3_integration_version:"+c2_integration_version+"\n"+"c3_soc_version:"+c2_soc_version+"\n"+"c3_mcu_version:"+c2_mcu_version+"\n"+"c3_switch_version:"+c2_switch_version+"\n"+"swc_interface software version:"+swc_interface_software_version+"\n";
        return true;
    }
    catch(const std::exception& e)
    {
         Log_Info("gd Exception json value2 ERROR: {}", e.what());
         return false;
    }
    

}
//设置dat里带run.sh --version信息
void CRecord::SetVersion(capilot::interface::InterfaceReply reply)
{
    WriteSftVersion();
    // WriteDiruanVersion();
    WriteVinVersion();  

    SetC2Version();
    //getC3BVersion();
    Version_total = SftVersion + VinVersion;
    
    Version_total_2 = Version_total;

    //获取interface接口
    ProtoInfo = reply.capilot_interface().SerializeAsString();
    Log_Info("Version_total size:{} ProtoInfo size:{},reply res:{},reply info:{}", Version_total.size(), ProtoInfo.size(),reply.res(),reply.info());
}

void CRecord::AddDiruan(string &diruan)
{
    Version_total_2 = Version_total + diruan;

    //Log_Info("Version_total_2 size:{} diruan size:{}", Version_total_2.size(), diruan.size());
}

void CRecord::WriteSftVersion()
{
    {
        std::string jsonStr;
        string tmpPath = global_data::g_data_path  + "SftVersion.txt";
        std::fstream out(tmpPath, std::fstream::trunc | std::fstream::in | std::fstream::out);
        if (!out)
        {
            Log_Info("get local file error!");
            return;
        }
        out.write(jsonStr.c_str(), jsonStr.size());
        out.close();
    }

    auto resSys = system("/app/ca_adas/run.sh --version >> /ds/ca_adas/SftVersion.txt"); 

    Log_Info("get SftVersion system ret:{}", resSys);

    if (!resSys)
    {
        fstream in("/ds/ca_adas/SftVersion.txt");
        SftVersion.clear();
        if (in)
        {
            stringstream buffer;//zjs_todo;内存泄露？
            buffer << in.rdbuf();
            SftVersion = buffer.str();
            in.close();
        }
        Log_Info("get SftVersion:{}", SftVersion);
    }

}

void CRecord::SetC2Version()
{
    {
        std::string jsonStr;
        string tmpPath = global_data::g_data_path  + "C2Version.txt";
        std::fstream out(tmpPath, std::fstream::trunc | std::fstream::in | std::fstream::out);
        if (!out)
        {
            Log_Info("get local file error!");
            return;
        }
        out.write(jsonStr.c_str(), jsonStr.size());
        out.close();
    }

    auto resSys = system("/app/ca_adas/run.sh --version |grep integration |  awk '{print $4}' >> /ds/ca_adas/C2Version.txt"); 

    Log_Info("get C2Version system ret:{}", resSys);

    if (!resSys)
    {
        fstream in("/ds/ca_adas/C2Version.txt");
        C2Version.clear();
        if (in)
        {
            stringstream buffer;//zjs_todo;内存泄露？
            buffer << in.rdbuf();
            C2Version = buffer.str();
            CommonOprString::deletEnter(C2Version);
            in.close();
        }
        Log_Info("get C2Version:{}", C2Version);//zjs_tmp_gailog;
    }

}

string CRecord::GetC2Version()
{
    return C2Version;
}

void CRecord::WriteDiruanVersion()
{
    {
        std::string jsonStr;
        string tmpPath = global_data::g_data_path  + "DiruanVersion.txt";
        std::fstream out(tmpPath, std::fstream::trunc | std::fstream::in | std::fstream::out);
        if (!out)
        {
            Log_Info("get local file error!");
            return;
        }
        out.write(jsonStr.c_str(), jsonStr.size());
        out.close();
    }

    auto resSys = system("/app/usr/bin/get_version s >> /ds/ca_adas/DiruanVersion.txt");
    Log_Info("get DiruanVersion system ret:{}", resSys);

    if (!resSys)
    {
        fstream in("/ds/ca_adas/DiruanVersion.txt");
        DiruanVersion.clear();
        if (in)
        {
            stringstream buffer;
            buffer << in.rdbuf();
            DiruanVersion = buffer.str();
            in.close();
        }
        Log_Info("get DiruanVersion:{}", DiruanVersion);//zjs_tmp_gailog;
    }

}

void CRecord::WriteVinVersion()
{
    {
        std::string jsonStr;
        string tmpPath = global_data::g_data_path  + "VinVersion.txt";
        std::fstream out(tmpPath, std::fstream::trunc | std::fstream::in | std::fstream::out);
        if (!out)
        {
            Log_Info("get local file error!");
            return;
        }
        out.write(jsonStr.c_str(), jsonStr.size());
        out.close();
    }

    auto resSys = system("cat /data/ca_adas/config/global_config.yaml | grep VIN >> /ds/ca_adas/VinVersion.txt");
    Log_Info("get VinVersion system ret:{}", resSys);

    if (!resSys)
    {
        fstream in("/ds/ca_adas/VinVersion.txt");
        VinVersion.clear();
        if (in)
        {
            stringstream buffer;
            buffer << in.rdbuf();
            VinVersion = buffer.str();
            in.close();
        }
        Log_ERROR("get VinVersion:{}", VinVersion);//zjs_tmp_gailog;
    }

}
